package com.sc.nft.dao;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.meta.component.base.api.CommonResult;
import com.meta.user.client.api.MetaUserClient;
import com.meta.user.client.req.MetaUserInfoReq;
import com.sc.nft.dto.UserRecommendDTO;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.dto.EarningsListDTO;
import com.sc.nft.entity.dto.PromotionRewardsDTO;
import com.sc.nft.entity.dto.SpecialRewardDTO;
import com.sc.nft.entity.dto.UserManageDaoDTO;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.DaoLevelTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.mapper.UserInfoMapper;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.sc.nft.sup.ErrorCode.OPERATE_FAIL;

/**
 * 注：移除父类是为了收敛方法集（原因是缺少接口约束，方法可能涉及数据写入，用户中台迁移过渡期会有两份数据，因此不能直接单方面写入）
 * <p>
 * (sc_user_info)数据DAO
 *
 * @author Sun
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-05-29 10:36:55
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class UserInfoDao {

    @Getter
    private final UserInfoMapper baseMapper;

    private final MetaUserClient metaUserClient;

    public UserInfo getById(Long id) {
        return baseMapper.selectById(id);
    }

    public UserInfo getOne(Wrapper<UserInfo> query) {
        return baseMapper.selectOne(query);
    }

    public int count(Wrapper<UserInfo> query) {
        return SqlHelper.retCount(getBaseMapper().selectCount(query));
    }

    public int count() {
        return count(Wrappers.emptyWrapper());
    }

    public Page<UserInfo> page(Page page) {
        return baseMapper.selectPage(page, Wrappers.emptyWrapper());
    }

    public List<UserInfo> list(Wrapper<UserInfo> wrapper) {
        return baseMapper.selectList(wrapper);
    }

    /**
     * 马特DAO-用户列表
     *
     * @param userManageDaoDTO
     * @return
     */
    public Page<UserManageDaoVO> mateDaoUserList(UserManageDaoDTO userManageDaoDTO) {
        return baseMapper.mateDaoUserList(userManageDaoDTO.toMp(), userManageDaoDTO);
    }

    /**
     * 马特DAO-用户列表,某个用户详情
     *
     * @param userTel
     * @param recommendUserIdList
     * @return
     */
    public UserMangeDaoUserInfoVO userMangeDaoUserInfo(String userTel, String recommendUserIdList) {
        return baseMapper.userMangeDaoUserInfo(userTel, recommendUserIdList);
    }

    /**
     * 马特DAO-推广奖励列表
     *
     * @param promotionRewardsDTO
     * @return
     */
    public Page<PromotionRewardsVO> promotionRewards(PromotionRewardsDTO promotionRewardsDTO) {
        return baseMapper.promotionRewards(promotionRewardsDTO.toMp(), promotionRewardsDTO);
    }

    /**
     * 马特DAO-用户信息,直推列表
     *
     * @param page
     * @return
     */
    public Page<MaTeUserMangeDaoGeneralEarningsDirectlyListVO> mateUserMangeDaoGeneralEarningsDirectlyList(Page page, Long userId) {
        return baseMapper.mateUserMangeDaoGeneralEarningsDirectlyList(page, userId);
    }

    /**
     * 马特DAO-用户信息,间推列表
     *
     * @param page
     * @return
     */
    public Page<MaTeUserMangeDaoGeneralEarningsIndirectListVO> maTeUserMangeDaoGeneralEarningsIndirectList(Page page, Long userId) {
        return baseMapper.maTeUserMangeDaoGeneralEarningsIndirectList(page, userId);
    }

    /**
     * 特殊奖励
     *
     * @param specialRewardDTO
     * @return
     */
    public Page<SpecialRewardVO> specialReward(SpecialRewardDTO specialRewardDTO) {
        return baseMapper.specialReward(specialRewardDTO.toMp(), specialRewardDTO);
    }

    /**
     * 用户收益列表
     *
     * @param earningsListDTO
     * @return
     */
    public Page<UserInfoEarningsVO> userInfoEarningsList(EarningsListDTO earningsListDTO) {
        return baseMapper.userInfoEarningsList(earningsListDTO.toMp(), earningsListDTO);
    }

    public List<HashMap> findPositionRanking() {
        return baseMapper.findPositionRanking();
    }

    public HashMap findPositionRankingById(Long id) {
        return baseMapper.findPositionRankingById(id);
    }

    public List<HashMap> findInviteRanking() {
        return baseMapper.findInviteRanking();
    }

    public HashMap findInviteRankingById(Long id) {
        return baseMapper.findInviteRankingById(id);
    }

    public UserInfo getOneByInviteCode(String inviteCode) {
        LambdaQueryWrapper<UserInfo> inviteUserWrapper = new LambdaQueryWrapper<>();
        inviteUserWrapper.eq(UserInfo::getInviteCode, inviteCode);
        return getOne(inviteUserWrapper);
    }

    public UserInfo getByUUID(String uuid) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getUserUuid, uuid);
        return getOne(wrapper);
    }

    public UserInfo getBySandWithUUid(String uuid) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getSandWithdrawUuid, uuid);
        return getOne(wrapper);
    }

    public boolean addInviteNumByUser(UserInfo userInfo) {
        UpdateWrapper<UserInfo> inviteUserUpdateWrapper = new UpdateWrapper<>();
        inviteUserUpdateWrapper.eq("id", userInfo.getId());
        inviteUserUpdateWrapper.setSql("invite_num = invite_num + " + 1);
        return update(inviteUserUpdateWrapper);
    }

    public UserInfo getOneByUserTel(String userTel) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getUserTel, userTel);
        wrapper.last("limit 1");
        return getOne(wrapper);
    }

    public UserInfo loginByTel(String userAccount) {
        LambdaQueryWrapper<UserInfo> userLoginLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLoginLambdaQueryWrapper.eq(UserInfo::getUserTel, userAccount);
        userLoginLambdaQueryWrapper.eq(UserInfo::getIsUser, 1);
        return getOne(userLoginLambdaQueryWrapper);
    }

    public List<UserInfo> getListByRecommendUserId(Long recommendUserId) {
        LambdaQueryWrapper<UserInfo> userInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userInfoLambdaQueryWrapper.eq(UserInfo::getRecommendUserId, recommendUserId);
        userInfoLambdaQueryWrapper.last("order by id desc");
        return list(userInfoLambdaQueryWrapper);
    }

    public List<UserInfo> getRecommendListByUserId(Long userId) {
        LambdaQueryWrapper<UserInfo> userInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userInfoLambdaQueryWrapper.eq(UserInfo::getRecommendUserId, userId);
        return list(userInfoLambdaQueryWrapper);
    }

    public List<UserInfo> findListByIsAddr() {
        LambdaQueryWrapper<UserInfo> userInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userInfoLambdaQueryWrapper.eq(UserInfo::getIsAddr, Boolean.FALSE);
        return list(userInfoLambdaQueryWrapper);
    }

    public Page<UserManageVO> pageUserInfo(String userUuid, String nickName, String userTel, Date startDate, Date endDate, String address, int pageNo, int pageSize) {
        return baseMapper.pageUserInfo(userUuid, nickName, userTel, address, new Page(pageNo, pageSize));
    }

    public List<CollectionByUserVO> collectionByUser(Long userId, String firstTitle) {
        return baseMapper.collectionByUser(userId, firstTitle);
    }

    public List<CollectionByUserDetailVO> collectionByUserDetail(Long userId, Long collectionId) {
        return baseMapper.collectionByUserDetail(userId, collectionId);
    }

    public Page<UserInfo> airdropGrantUser(int pageNo, int pageSize, String nickName, String userUuid, String userTel) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(userUuid != null, UserInfo::getUserUuid, userUuid);
        wrapper.like(nickName != null, UserInfo::getNickName, nickName);
        wrapper.like(userTel != null, UserInfo::getUserTel, userTel);
        wrapper.eq(UserInfo::getIsFreeze, Boolean.FALSE);
        return baseMapper.selectPage(new Page<>(pageNo, pageSize), wrapper);
    }

    public List<UserInfo> getTeamOwnerList(String recommendUserId) {
        return baseMapper.getTeamOwnerList(recommendUserId);
    }

    public void setPrivilegeLevel(Long userId, Integer level) {
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserInfo::getId, userId);
        wrapper.set(UserInfo::getPrivilegeLevel, level);
        update(wrapper);
    }

    public Page<SimpleUserVO> simpleUserList(String userTel, int pageNo, int pageSize) {
        return baseMapper.simpleUserList(userTel, new Page(pageNo, pageSize));
    }

    public List<UserInfo> getListByRecommendId(Long id) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getRecommendUserId, id);
        return list(wrapper);
    }

    public Boolean addHoldToen(BigDecimal productPrice, Long id) {
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.setSql("hold_token = hold_token + " + productPrice);
        return update(wrapper);
    }

    @Transactional
    public Boolean updateUserLevel(DaoLevelTypeEnum daoLevelType, Long id) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setLevel(daoLevelType.getCode());
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        log.info("执行用户升级:" + "id: " + id + " 等级:" + daoLevelType.getDescription());
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserInfo::getId, id);
        wrapper.set(UserInfo::getLevel, daoLevelType.getCode());
        wrapper.set(UserInfo::getLevelName, daoLevelType.getDescription());
        return update(wrapper);
    }

    public Page<UserInfo> getRecommendListByUserIdQueryConditions(Long userId, String time, String holdToken, String secondaryHoldToken, Integer pageNo, Integer pageSize) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getRecommendUserId, userId);
        if (StrUtil.isNotBlank(time) && time.equals("DESC")) {
            wrapper.last("order by id desc");
        } else if (StrUtil.isNotBlank(holdToken) && holdToken.equals("DESC")) {
            wrapper.last("order by hold_token desc");
        } else if (StrUtil.isNotBlank(secondaryHoldToken) && secondaryHoldToken.equals("DESC")) {
            wrapper.last("order by secondary_hold_token desc");
        } else if (StrUtil.isNotBlank(time) && time.equals("ASC")) {
            wrapper.last("order by id ");
        } else if (StrUtil.isNotBlank(holdToken) && holdToken.equals("ASC")) {
            wrapper.last("order by hold_token ");
        } else if (StrUtil.isNotBlank(secondaryHoldToken) && secondaryHoldToken.equals("ASC")) {
            wrapper.last("order by secondary_hold_token ");
        }
        return baseMapper.selectPage(new Page<>(pageNo, pageSize), wrapper);
    }

    public BigDecimal getSumHoldTokenByRecommendId(Long recommendId) {
        return baseMapper.getSumHoldTokenByRecommendId(recommendId);
    }

    public BigDecimal getSumSecondaryHoldTokenByRecommendId(Long recommendId) {
        return baseMapper.getSumSecondaryHoldTokenByRecommendId(recommendId);
    }

    @Transactional
    public Boolean setIsValid(Long id) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setIsValid(true);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.setSql("real_valid_invite_num = real_valid_invite_num + " + 1 + ",is_valid=1");
        return update(wrapper);
    }

    public Boolean addSecondaryHoldToken(Long id, BigDecimal buyPrice) {
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.setSql("secondary_hold_token = secondary_hold_token + " + buyPrice);
        return update(wrapper);
    }

    public List<UserInfo> getUserInfoList(List<String> userTels) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserInfo::getUserTel, userTels);
        return list(wrapper);
    }

    public List<UserInfo> getUserCityServerCentre() {
        return baseMapper.getUserCityServerCentre();
    }

    public Boolean updateIsAddrById(Long id, Boolean isAddr) {
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("is_addr", isAddr);
        return update(wrapper);
    }

    @Transactional
    public Boolean updateUserByIdGroup(Long id, Integer addGroup) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setAddGroup(addGroup);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserInfo::getId, id);
        wrapper.set(UserInfo::getAddGroup, addGroup);
        return update(wrapper);
    }

    @Transactional
    public Boolean updatePwdById(Long id, String newPwd) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setPwd(newPwd);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("pwd", newPwd);
        return update(wrapper);
    }

    public void openAccountSuccess(Long id, String masterAccount) {
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(UserInfo::getSandAccountOpen, true);
        wrapper.set(UserInfo::getSandMasterAccount, masterAccount);
        wrapper.eq(UserInfo::getId, id);
        update(wrapper);
    }

    public void sandFaceVerify(Long id) {
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(UserInfo::getSandFaceVerify, true);
        wrapper.eq(UserInfo::getId, id);
        update(wrapper);
    }

    public void sandPwd(Long id) {
        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(UserInfo::getSandPayPwd, true);
        wrapper.eq(UserInfo::getId, id);
        update(wrapper);
    }

    /**
     * 清除用户绑卡实名制状态，并且重置杉德支付卡绑卡id编号
     *
     * @param userId
     */
    @Transactional
    public void clearUserIsSmAndOutSideKey(Long userId) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(userId);
        req.setIsSm(Boolean.FALSE);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", userId);
        wrapper.set("is_sm", Boolean.FALSE);
        wrapper.set("out_side_key", Long.toHexString(SystemClock.now() / 10));
        update(wrapper);
    }

    public Boolean updateOutSideKeyById(Long id) {
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("out_side_key", Long.toHexString(SystemClock.now() / 10));
        return update(wrapper);
    }

    /**
     * 根据手机号获取用户基本信息
     *
     * @param userTel
     * @return
     */
    public UserTelGetUserInfoVO userTelGetUserInfo(String userTel) {
        return baseMapper.userTelGetUserInfo(userTel);
    }

    public Integer getPartnerCount() {
        return baseMapper.getPartnerCount();
    }

    public Integer getCountByLevel(DaoLevelTypeEnum levelTypeEnum) {
        return baseMapper.getCountByLevel(levelTypeEnum.getCode());
    }

    public Integer getCount() {
        return baseMapper.getCount();
    }

    /**
     * 获取用户实名并且没有加入官方群的数据,数据根据分页数据来.
     *
     * @return
     */
    public List<UserInfo> getUserIsSmAndIsOfficialLimit(Page page, List list) {
        return baseMapper.getUserIsSmAndIsOfficialLimit(page, list);
    }

    public Integer getYesterDayCount() {
        return baseMapper.getYesterDayCount();
    }

    public Integer getYesterDayCountByDay(String day) {
        return baseMapper.getYesterDayCountByDay(day);
    }

    public Integer getCountRecommendUserId(Long recommendUserId) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getRecommendUserId, recommendUserId);
        return count(wrapper);
    }


    public Integer getByListUserIdCountValid(Long userId, Boolean urbanServiceCenter) {
        return baseMapper.getByListUserIdCountValid(userId, urbanServiceCenter);
    }

    public List<UserWithCollectionSimpleVO> getDestroyCount(List<Long> collectionIdList) {
        return baseMapper.getDestroyCount(collectionIdList);
    }

    public Integer getOneDestroyCount(Long collectionId) {
        return baseMapper.getOneDestroyCount(collectionId);
    }

    public List<UserWithCollectionSimpleVO> countCollection(List<Long> collectionIdList) {
        return baseMapper.countCollection(collectionIdList);
    }

    public List<UserWithCollectionSimpleVO> marketAccountCollection(List<Long> collectionIdList, List<Long> userIdList) {
        return baseMapper.marketAccountCollection(collectionIdList, userIdList);
    }

    public List<UserWithCollectionSimpleVO> userCount(List<Long> collectionIdList) {
        return baseMapper.userCount(collectionIdList);
    }

    public List<UserWithCollectionSimpleVO> marketAccountCount(List<Long> collectionIdList, List<Long> userIdList) {
        return baseMapper.marketAccountCount(collectionIdList, userIdList);
    }

    public String getUserTelById(Long id) {
        return Optional.ofNullable(getById(id)).map(UserInfo::getUserTel).orElse(null);
    }
    public String getNickNameById(Long id) {
        return Optional.ofNullable(getById(id)).map(UserInfo::getNickName).orElse(null);
    }

    public List<Long> getDownUserIds(Long userId) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(UserInfo::getId);
        wrapper.eq(UserInfo::getRecommendUserId, userId);
        return getBaseMapper().selectObjs(wrapper).stream().filter(Objects::nonNull).map((x) -> (Long) x).collect(Collectors.toList());
    }

    public Boolean userRealName(Long userId) {
        return updateIsSm(userId, true);
    }

    public List<UserInfo> getByIdList(List<Long> userIdList) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserInfo::getId, userIdList);
        return list(wrapper);
    }

    @Transactional
    public void updateNickNameAndAvatarImg(UserInfo userInfo) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(userInfo.getId());
        req.setNickName(userInfo.getNickName());
        req.setAvatarImg(userInfo.getAvatarImg());
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(UserInfo::getNickName, userInfo.getNickName());
        wrapper.set(UserInfo::getAvatarImg, userInfo.getAvatarImg());
        wrapper.eq(UserInfo::getId, userInfo.getId());
        update(wrapper);
    }

    public List<BatchEnterIntegrationShowListVO> userTelByAssets(List<String> userTelList) {
        return baseMapper.userTelByAssets(userTelList);
    }

    public List<UserInfo> getListByTelList(List<String> userTelList) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserInfo::getUserTel, userTelList);
        return baseMapper.selectList(wrapper);
    }

    // --------------------------- CUD方法，请勿随意增加，用户表部分字段迁移到用户中台，需要实现双写 ---------------------------

//    /**
//     * 该方法仅限内部使用
//     *
//     * @param entity
//     * @return
//     */
//    private Boolean save(UserInfo entity) {
//        return SqlHelper.retBool(getBaseMapper().insert(entity));
//    }

    /**
     * 创建用户（同时在用户中台创建）
     */
    public Boolean saveWithSync(UserInfo entity) {
        MetaUserInfoReq req = new MetaUserInfoReq();
        BeanUtils.copyProperties(entity, req);
        CommonResult<Long> result = metaUserClient.createUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        entity.setId(result.getData());
        Integer i = this.baseMapper.insertUser(entity);
        return i > 0;
    }

    /**
     * 本地插入，用户中台数据同步实现
     */
    public Boolean saveForSyncConsumer(UserInfo entity) {
        Integer i = this.baseMapper.insertUser(entity);
        return i > 0;
    }

    /**
     * 受限更新方法，不能更新用户基础信息（相关接口已迁移到用户中台）
     * <p>
     * #张立坤 更新方法全部收敛到 UserInfoDao 类中，避免出现更新未知字段的调用出现，解决双写过程中出现遗漏的情况
     *
     * @param wrapper 非空
     */
    private boolean update(Wrapper<UserInfo> wrapper) {
        return SqlHelper.retBool(getBaseMapper().update(null, wrapper));
    }

    /**
     * 受限更新方法
     * <p>
     * #张立坤 更新方法全部收敛到 UserInfoDao 类中，避免出现更新未知字段的调用出现，解决双写过程中出现遗漏的情况
     *
     * @param entity 非空
     */
    private boolean updateById(UserInfo entity) {
        return SqlHelper.retBool(baseMapper.updateById(entity));
    }

    /**
     * 注：业务端请勿使用该方法，仅供架构组实现用户台过渡阶段同步数据用！！
     */
    public void updateForSyncConsumer(UserInfo entity) {
        updateById(entity);
    }

    /**
     * 冻结用户
     */
    @Transactional
    public void freeze(long userId) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(userId);
        req.setIsFreeze(true);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);
        userInfo.setIsFreeze(true);
        updateById(userInfo);
    }

    @Transactional
    public boolean updateUserTelById(Long id, String changeAfterUserTel) {
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setUserTel(changeAfterUserTel);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));

        LambdaUpdateWrapper<UserInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserInfo::getId, id);
        wrapper.set(UserInfo::getUserTel, changeAfterUserTel);
        return update(wrapper);
    }

    @Transactional
    public void updateTransactionPassword(Long id, String transactionPassword) {

        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("transaction_password", transactionPassword);
        update(updateWrapper);
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setTransactionPassword(transactionPassword);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));
    }

    public void updateRecommendUserIdList(Long id, String updateRecommendUserIdList) {
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("recommend_user_id_list", updateRecommendUserIdList);
        log.info("用户id :{} 邀请链为: {}", id, updateRecommendUserIdList);
        update(updateWrapper);
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setRecommendUserIdList(updateRecommendUserIdList);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));
    }

    public Boolean updateIsPartner(Long id, int isPartner) {
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("is_partner", isPartner);
        return update(updateWrapper);
    }

    public void updateIsTransferCheckFace(Long id, Boolean isTransferCheckFace) {
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("is_transfer_check_face", isTransferCheckFace);
        update(wrapper);
    }

    @Transactional
    public boolean updateIsSm(Long id, Boolean isSm) {
        boolean flag;
        UpdateWrapper<UserInfo> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("is_sm", isSm);
        flag = update(wrapper);
        if (flag) {
            // 同步更新用户中台数据  先执行本地事务再调用远程 远程异常回滚本地事务 flag只是为了返回一个值
            MetaUserInfoReq req = new MetaUserInfoReq();
            req.setId(id);
            req.setIsSm(isSm);
            CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
            Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));
        }
        return flag;
    }

    @Transactional
    public void restoreAccount(UserInfo userInfo) {
        // 变更字段范围
        // userInfo.setIsSm(false);
        // userInfo.setSandAccountOpen(false);
        // userInfo.setSandFaceVerify(false);
        // userInfo.setSandPayPwd(false);
        // userInfo.setSandMasterAccount(null);
        // userInfo.setSandWithdrawUuid(String.valueOf(snowflakeNextId));


        updateById(userInfo);

        // 同步更新用户中台数据
        if (userInfo.getIsSm() != null) {
            MetaUserInfoReq req = new MetaUserInfoReq();
            req.setId(userInfo.getId());
            req.setIsSm(userInfo.getIsSm());
            CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
            Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));
        }
    }

    @Transactional
    public void updateUserInformation(Long id, String nickName, String avatarImg, Boolean isFreeze, Boolean giftPermission) {

        UserInfo userInfo = new UserInfo();
        userInfo.setId(id);
        userInfo.setNickName(nickName);
        userInfo.setAvatarImg(avatarImg);
        userInfo.setIsFreeze(isFreeze);
        userInfo.setGiftPermission(giftPermission);
        updateById(userInfo);
        // 同步更新用户中台数据
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(id);
        req.setNickName(nickName);
        req.setAvatarImg(avatarImg);
        req.setIsFreeze(isFreeze);
        req.setGiftPermission(giftPermission);
        CommonResult<Boolean> result = metaUserClient.updateUserInfo(req);
        Assert.isTrue(result.isSuccessful(), () -> new GlobalRunTimeException(OPERATE_FAIL));
    }

    public UserInfo getByUserTel(String userTel) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getUserTel, userTel);
        wrapper.orderByDesc(UserInfo::getId);
        wrapper.last("limit 1");
        return getOne(wrapper);
    }


    /**
     * 获取城市服务中心用户下有效的用户数量（排除品牌方DAO用户下的）
     *
     * @param serviceCenterUserId
     * @param daoUserId
     * @return
     */
    public Integer getCountValidByUserId(Long serviceCenterUserId, Long daoUserId) {
        return baseMapper.getCountValidByUserId(serviceCenterUserId, daoUserId);
    }

    /**
     * 获取品牌拉新人数
     *
     * @param daoUserId
     * @param daoOnlineTime dao上线时间
     * @return
     */
    public Integer getDaoNewUserNum(Long daoUserId, Date daoOnlineTime) {
        return baseMapper.getDaoNewUserNum(daoUserId, daoOnlineTime);
    }

    /**
     * 获取服务中心拉新人数
     *
     * @param serviceCenterUserId
     * @param daoUserId
     * @param daoOnlineTime       dao上线时间
     * @return
     */
    public Integer getServiceCenterNewUserNum(Long serviceCenterUserId, Long daoUserId, Date daoOnlineTime) {
        return baseMapper.getServiceCenterNewUserNum(serviceCenterUserId, daoUserId, daoOnlineTime);
    }

    public List<UserInfo> getNotInitUserList() {
        return baseMapper.getNotInitUserList();
    }

    public void updateSandInfo(Long id, boolean sandAccountOpen, boolean sandFaceVerify, boolean sandPayPwd) {
        UserInfo entity = new UserInfo();
        entity.setId(id);
        entity.setSandAccountOpen(sandAccountOpen);
        entity.setSandFaceVerify(sandFaceVerify);
        entity.setSandPayPwd(sandPayPwd);

        // 只更新 metago 库下用户数据
        updateById(entity);
    }

    @Transactional
    public void logicDelete(Long id, String newTel) {
        UserInfo user = new UserInfo();
        user.setId(id);
        user.setUserTel(newTel);
        user.setIsFreeze(Boolean.TRUE);
        user.setPwd("a2a52d6f5abe9e050c692b134551733e");
        user.setNickName(DesensitizedUtil.mobilePhone(newTel));
        user.setIsSm(Boolean.FALSE);

        // 本地更新
        updateById(user);

        // 远程更新
        MetaUserInfoReq req = new MetaUserInfoReq();
        req.setId(user.getId());
        req.setUserTel(user.getUserTel());
        req.setIsFreeze(user.getIsFreeze());
        req.setPwd(user.getPwd());
        req.setNickName(user.getNickName());
        req.setIsSm(user.getIsSm());
        metaUserClient.updateUserInfo(req);
    }

    public List<UserCollectionConsensusExcelParsingListVO> userTelByConsensus(List<String> userTelList) {
        return baseMapper.userTelByConsensus(userTelList);
    }

    public List<Long> listRecommendByUserId(Long userId) {
        return baseMapper.listRecommendByUserId(userId);
    }



    public List<UserRecommendDTO> listRecommendByUserIdList(List<Long> userIdList) {
        return baseMapper.listRecommendByUserIdList(userIdList);
    }

}